package uk.co.agileworks.bidpirate.bidding;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;

import uk.co.agileworks.bidpirate.model.Bid;
import uk.co.agileworks.bidpirate.model.Status;
import uk.co.agileworks.bidpirate.service.BusinessLogic;
import uk.co.agileworks.bidpirate.service.DAO;
import uk.co.agileworks.bidpirate.service.EbayFacade;
import uk.co.agileworks.bidpirate.service.EbaySession;

@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.NO)
public final class BidTask implements Runnable {

	private static final Logger LOGGER = LoggerFactory.getLogger(BidTask.class);
	private static final long TO_MILLISECONDS = 1000;
	
	@Autowired
	private BusinessLogic businessLogic;
	@Autowired
	private DAO dao;
	@Autowired
	private EbayFacade ebayFacade;
	@Resource
	private Integer secondsBeforeConfirm;
	
	private Bid bid;

	public BidTask(Bid bid) {
		this.bid = bid;
	}

	@Override
	public void run() {
		LOGGER.info("Begin bidding. {" + bid + "}");
		EbaySession ebaySession = ebayFacade.newEbaySession();
		try {
			if (ebaySession.signIn(bid.getUser())) {
				ebaySession.placeBid(bid);
				long timeLeft = bid.getItem().getEndTime().getMillis() - System.currentTimeMillis();
				sleep(timeLeft - secondsBeforeConfirm * TO_MILLISECONDS);
				ebaySession.confirmBid();
				sleep(secondsBeforeConfirm * TO_MILLISECONDS);
				String itemUrl = ebayFacade.getItemUrl(bid.getItem().getItemNumber());
				if (ebaySession.isItemEnded(itemUrl)) {
					bid.getItem().setPrice(ebaySession.getItemPrice());
					bid.setStatus(ebaySession.isItemWon() ? Status.WON : Status.LOST);
				} else {
					bid.setStatus(Status.UNKNOWN);
					LOGGER.warn("Failed to determine final item state. {" + bid.getItem() + "}");
				}
			} else {
				LOGGER.error("Failed to log in user. {" + bid.getUser() + "}");
			}
		} catch (Exception e) {
			LOGGER.error(e.toString());
		} finally {
			if (bid.getStatus() == Status.BIDDING) {
				bid.setStatus(Status.FAILED);
			}
			dao.saveOrUpdateBid(bid);
			if (bid.getStatus() == Status.WON || bid.getStatus() == Status.FAILED) {
				businessLogic.stopGroup(bid);
			}
			ebaySession.signOut();
			LOGGER.info("End bidding. {" + bid + "}");
		}
	}
	
	static void sleep(long millis) {
		LOGGER.debug("Sleeping " + millis + "ms");
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			LOGGER.warn(e.getMessage());
		}
	}

}
